import { ref } from "vue";
import * as d3 from "d3";
import { getNodeColor, getNodeImg } from "./util";
import { sum, values,forEach } from "lodash";

const node_w = 100,
    node_h = 100;
const tooltip_w = 156,
    tooltip_h = 50;
const img_w = 30,
    img_h = 30;
const alarmTypes = ["namespace", "service", "workload", "node", "pod"];
export default function useChart({selectNodes, appClick}) {
    // 调用链点击节点同时出现多个分层拓扑，d3区别不了加的标识符
    const id = ref(Date.now());
    const chartRef = ref();
    const showCheckRect = ref(false)
    // 勾选框选择节点事件
    const transformValueBuild = (str) => {
        let str1 = str.substring(str.indexOf("(") + 1, str.indexOf(")"));
        return str1.split(",");
    };
    // 是否显示遮罩层
    const showMask = (maskId) => {
        d3.selectAll(".mask_rect").attr(
            "style",
            `display: ${maskId ? "block" : "none"}`
        );
        if (maskId) {
            d3.select(maskId).attr("style", "display: none");
        }
    };
    let space_left;

    // * 绘制箭头
    const drawArrow = ( g) => {
        const nodeWarp = g.append("g").attr("id", `node_warp-${id.value}`);
        const LineWarp = g.append("g").attr("id", `line_wrap-${id.value}`);
        const downTooltipWarp = g.append("g").attr("id", "tooltip_warp");
        const defs = LineWarp.append("defs"); // defs定义可重复使用的元素
        const arrowheads = defs
            .append("marker") // 创建箭头
            .attr("id", `arrow-${id.value}`)
            .attr("markerUnits", "strokeWidth")
            .attr("markerWidth", 8)
            .attr("markerHeight", 6)
            .attr("viewBox", "0 0 10 10")
            .attr("refX", 9)
            .attr("refY", 5)
            .attr("orient", "auto");
        arrowheads
            .append("path")
            .attr("d", "M 0 0 L 10 5 L 0 10 L 4 5 z")
            .attr("fill", "#bdbdbd");
        return {
            nodeWarp,
            downTooltipWarp,
            LineWarp
        };
    };
    const selectNode = (d) => {
        let nodeLength = _.filter(
            this.props.nodes,
            (option) => option.type === d.type
        ).length;
        let nodeIdx = _.findIndex(selectNodes, { id: d.id });
        if (nodeIdx > -1) {
            d3.select(`#${d.type}_check_${d.idx}`)
                .select("path")
                .attr("style", "display: none");

            selectNodes.value.splice(nodeIdx, 1);
            if (selectNodes.value.length !== nodeLength) {
                let left = d3
                    .select(`#btn_all_${d.type}`)
                    .select("rect")
                    .attr("x");
                d3.select(`#btn_all_${d.type}`)
                    .select("text")
                    .text("全选")
                    .attr("x", function () {
                        let textlen = this.getComputedTextLength();
                        return parseFloat(left) + (80 - textlen) / 2;
                    });
            }
            // this.setState({ selectNodes });
        } else {
            d3.select(`#${d.type}_check_${d.idx}`)
                .select("path")
                .attr("style", "display: block");
            // let { selectNodes } = this.state;
            selectNodes.value.push(d);
            if (selectNodes.value.length === nodeLength) {
                let left = d3
                    .select(`#btn_all_${d.type}`)
                    .select("rect")
                    .attr("x");
                d3.select(`#btn_all_${d.type}`)
                    .select("text")
                    .text("取消全选")
                    .attr("x", function () {
                        let textlen = this.getComputedTextLength();
                        return parseFloat(left) + (80 - textlen) / 2;
                    });
            }
            this.setState({ selectNodes });
        }
    };
    /**
     * 每个层级绘制指标对比按钮的公共方法
     * @param {*} element append按钮父节点dom
     * @param {*} id 按钮id
     * @param {*} width 按钮所在层级宽度
     * @param {*} height 按钮所在层级高度
     * @param {*} text 按钮的文本信息
     * @param {*} num 计算按钮布局的字段，根据该字段计算按钮的纵向y坐标
     */
    const appendRightButton = (element, id, width, height, text, num) => {
        let left = width - 90;
        let top;
        if (num <= 0) {
            num = Math.abs(num);
            top = height / 2 - (24 * (0.5 + num) + 10 * num);
        } else {
            top = height / 2 + (24 * 0.5 + 10);
        }
        let rigthBtn = element
            .append("g")
            .attr("id", id)
            .attr("class", `right_btn_warp ${text === "取消" && "red_text"}`);
        rigthBtn
            .append("rect")
            .attr("class", "right_button")
            .attr("rx", 4)
            .attr("ry", 4)
            .attr("x", left)
            .attr("y", top);
        rigthBtn
            .append("text")
            .text(text)
            .attr("class", "right_button_text")
            .attr("x", function () {
                let textlen = this.getComputedTextLength();
                return left + (80 - textlen) / 2;
            })
            .attr("y", top + 16);
    };
    /**
     * 绘制节点层级，当对应类型的每个节点的数据都为0时不绘制该层级，并保存下绘制后各层级的宽度为后续的顶部调用线的位置和布局提供计算依据
     * @param {string} id 对应层级g的dom ID
     * @param {*} name 层级名称(终端,应用,数据库/中间件,网络设备,主机)
     * @param {*} list 对应层级的节点数组数据
     * @param {*} isPlay 回溯重绘，影响节点之间的距离有30 ——> 80
     */
    function setNode(
        width,
        nodeType,

        list,
        nodeWarp,
        idHightList,
        isPlay = false,
        isShowCompareIndex = false,
        nodeWidthRow
    ) {
        // printIdList.push(id);
        // let endRectWidth = 90,
        const uniId = id.value
        const back =
            isPlay &&
            nodeType.type === "pod" &&
            _.find(
                list,
                (item) =>
                    item.attribute.podLifeList &&
                    item.attribute.podLifeList.length
            );
        const space_w = back ? 60 : 30,
            min_space_left = 120,
            min_space_right = 80;
        let endRectHeight = back ? 200 : 160,
            img_top = back ? 80 : 30,
            rowNum = 1;
        // colNum 计算布局每行可以放多少个节点
        // min_space_left + rowNum * node_w + space_w * (rowNum - 1) = width
        let colNum = Math.floor(
            (width - min_space_left - min_space_right + space_w) /
                (node_w + space_w)
        );
        if (list.length > colNum) {
            rowNum = Math.ceil(list.length / colNum);
            endRectHeight = node_h * rowNum + img_top * (rowNum + 1);
            space_left = min_space_left;
        } else {
            space_left =
                (width - list.length * node_w - (list.length - 1) * space_w) /
                2;
        }
        // console.log(colNum, rowNum, endRectHeight);

        let cluster = nodeWarp
            .append("g")
            .attr("id", `${nodeType.value}-${id.value}`)
            .attr("class", "cluster")
            .attr(
                "transform",
                `translate(0, ${sum(values(idHightList)) || 0})`
            );
        // .attr('style', 'transform: translate(90px, 20px)');

        let bgRect = cluster.append("rect").attr("class", "bg_rect");
        let borderRect = cluster.append("rect").attr("class", "border_rect").attr('width', width).attr('height', 1);
        borderRect.attr('fill', '#E2E8F4').attr("y", endRectHeight);
        // 为每个层级的左侧append名称以及对应层级的节点数量
        cluster
            .append("text")
            .text(nodeType.title !== "Pod" ? nodeType.title : nodeType.title)
            .attr("class", "left_name")
            .attr("x", function () {
                let textlen = this.getComputedTextLength();
                return 50 - textlen / 2;
            })
            .attr("y", endRectHeight / 2 - 10);
        cluster
            .append("path")
            .attr("class", "left_line")
            .attr("d", `M10,${endRectHeight / 2}H90`);
        cluster
            .append("text")
            .text(list.length)
            .attr("class", "left_sum")
            .attr("x", function () {
                let textlen = this.getComputedTextLength();
                return 50 - textlen / 2;
            })
            .attr("y", endRectHeight / 2 + 20);

        let nodes = cluster.append("g").attr("class", "nodes");
        let imgWarp = nodes
            .selectAll("g")
            .data(list)
            .enter()
            .append("g")
            .attr("id", (d) => `${nodeType.value}_${d.idx}-${id.value}`)
            .attr("class", "node")
            .attr("transform", (d, i) => {
                if (rowNum > 1) {
                    nodeWidthRow.push({
                        row: Math.floor(i / colNum),
                        col: i % colNum,
                        ...d,
                    });
                    return `translate(${
                        min_space_left + (node_w + space_w) * (i % colNum)
                    }, ${
                        img_top + (img_top + node_h) * Math.floor(i / colNum)
                    })`;
                } else {
                    return `translate(${
                        space_left + (node_w + space_w) * i
                    }, ${img_top})`;
                }
            });
        imgWarp.on("click", (d) => {
            if (showCheckRect.value) {
                selectNode(d);
            }
        });
        imgWarp
            .append("circle")
            .attr("cx", 50)
            .attr("cy", 35)
            .attr("class", "node_box")
            .attr("r", 35)
            .style("fill", (d) => {
                return getNodeColor(d.status).fill;
            })
            .style("stroke", (d) => {
                return getNodeColor(d.status).stroke;
            })
            .append("title")
            .text((d) => {
                // console.log('d444', d);
                // if (d.type === 'pod' || d.type === 'node') {
                return d.exceptionMsg && d.exceptionMsg.replace(/,/g, "\r\n");
                // }
            });
        imgWarp
            .append("image")
            .attr("class", "node_image")
            .attr("x", (node_w - img_w) / 2)
            .attr("y", 20)
            .attr("width", img_w)
            .attr("height", img_h)
            .attr("xlink:href", (d) => {
                return getNodeImg(d.status, d.type);
            })
            .attr("cursor", (d) => {
                return d.type !== "vmservice" ? "pointer" : "default";
            })
            .on("click", (d) => {
                if (!showCheckRect.value) {
                    d3.event?.stopPropagation();
                    appClick(d);
                }
            })
            .append("title")
            .text((d) => {
                // console.log('d444', d);
                // if (d.type === 'pod' || d.type === 'node') {
                return d.exceptionMsg && d.exceptionMsg.replace(/,/g, "\r\n");
                // }
            });

        imgWarp
            .append("text")
            .text((d) => {
                let str;
                str = d.name;
                // if (d.type !== 'service' && d.type !== 'node') {
                //     str = d.name
                // } else {
                //     str = d.ip
                // }
                if (str.length > 15) {
                    return str.substring(0, 12) + "...";
                } else {
                    return str;
                }
            })
            .attr("class", "node_name")
            .attr("x", function () {
                let textlen = this.getComputedTextLength();
                return node_w / 2 - textlen / 2;
            })
            .attr("y", img_h + 60)
            .append("title")
            .text((d) => (d.ip ? `${d.name}\n${d.ip}` : d.name));

        if (nodeType.type === "pod") {
            imgWarp
                .append("rect")
                .attr("id", (d) => "pod" + d.sid + id.value)
                .attr("class", (d) =>
                    ["running", "complete"].indexOf(d.status.toLowerCase()) > -1
                        ? "pod_rect green"
                        : "pod_rect red"
                )
                .attr("x", node_w / 2 - 65 / 2)
                .attr("y", img_h + 65);

            imgWarp
                .append("text")
                .text((d) => d.status)
                .attr("class", (d) =>
                    ["running", "complete"].indexOf(d.status.toLowerCase()) > -1
                        ? "pod_status_text green"
                        : "pod_status_text red"
                )
                .attr("x", function (d) {
                    let textlen = this.getComputedTextLength();
                    d3.select(`#pod${d.sid}`)
                        .attr("width", textlen + 10)
                        .attr("x", node_w / 2 - textlen / 2 - 5);
                    return node_w / 2 - textlen / 2;
                })
                .attr("y", img_h + 77);
        }

        // append告警数跟异常数的数量
        if (alarmTypes.indexOf(nodeType.value) > -1) {
            forEach(list, (node) => {
                if (node.type !== "namespace" && node.alarmCount) {
                    nodeAppendAbnormal(
                        d3.select(`#${node.type}_${node.idx}`),
                        node.alarmCount > 99 ? "99+" : node.alarmCount,
                        "warnCount",
                        node_w,
                        0
                    );
                    // node.errorCount > 0 && _this.nodeAppendAbnormal(d3.select(`#${node.type}_${node.idx}`), node.errorCount > 99 ? '99+' : node.errorCount, 'errorCount', node_w, 0);
                    // node.warnCount > 0 && _this.nodeAppendAbnormal(d3.select(`#${node.type}_${node.idx}`), node.warnCount > 99 ? '99+' : node.warnCount, 'warnCount', node_w, node.errorCount > 0 ? 1 : 0);
                    // node.attribute && node.attribute.alarmInfo && node.attribute.alarmInfo.seriousAlarmCount > 0&&  _this.nodeAppendAbnormal(d3.select(`#${node.type}_${node.idx}`), node.attribute.alarmInfo.seriousAlarmCount > 99 ? '99+' : node.attribute.alarmInfo.seriousAlarmCount, 'errorCount', node_w, 0);
                    // node.attribute && node.attribute.alarmInfo && node.attribute.alarmInfo.normalAlarmCount > 0 &&  _this.nodeAppendAbnormal(d3.select(`#${node.type}_${node.idx}`), node.attribute.alarmInfo.normalAlarmCount > 99 ? '99+' : node.attribute.alarmInfo.normalAlarmCount, 'warnCount', node_w, node.attribute.alarmInfo.seriousAlarmCount > 0 ? 1 : 0);
                }
            });
        }
        //回溯不需要指标对比
        if (!isPlay) {
            // append指标对比的选择框
            let checkRect = imgWarp
                .append("g")
                .attr("class", "check_g_warp")
                .attr("style", "display: none")
                .attr("id", (d) => {
                    return `${d.type}_check_${d.idx}`;
                });

            checkRect
                .append("rect")
                .attr("x", 5)
                .attr("y", 5)
                .attr("rx", 2)
                .attr("ry", 2)
                .attr("class", "check_rect");
            checkRect
                .append("path")
                .attr("class", "check_mark")
                .attr("fill", "none")
                .attr("transform", "translate(3, 3.4)")
                .attr("d", "M4.1 7.2l2.5 2.6 5.6-5.8");

            checkRect.on("click", function (d) {
                d3.event.stopPropagation();
                selectNode(d);
            });
        }

        bgRect.attr("width", width).attr("height", endRectHeight);
        idHightList[nodeType.value] = endRectHeight;

        // 为每个层级的右侧append 指标对比的按钮,回溯不需要
        if (
            isShowCompareIndex &&
            list.length >= 2 &&
            alarmTypes.indexOf(nodeType.value) > -1 &&
            !isPlay
        ) {
            appendRightButton(
                cluster,
                `btn_compare_${nodeType.value}`,
                width,
                endRectHeight,
                "指标对比",
                0
            );
            let rigthBtnDetail = cluster
                .append("g")
                .attr("id", `detail_btn_warp_${nodeType.value}-${uniId}`)
                .attr("class", "right_btn_detail_warp")
                .attr("style", "display: none");
            appendRightButton(
                rigthBtnDetail,
                `btn_cancel_${nodeType.value}`,
                width,
                endRectHeight,
                "取消",
                1
            );
            appendRightButton(
                rigthBtnDetail,
                `btn_confirm_${nodeType.value}`,
                width,
                endRectHeight,
                "确定",
                0
            );
            appendRightButton(
                rigthBtnDetail,
                `btn_all_${nodeType.value}`,
                width,
                endRectHeight,
                "全选",
                -1
            );
            // 点击指标对比
            d3.select(`#btn_compare_${nodeType.value}`).on(
                "click",
                function () {
                    showCheckRect.value = true;
                    showMask(`#${nodeType.value}_mask`);
                    d3.select(this).attr("style", "display: none");
                    d3.select(
                        `#detail_btn_warp_${nodeType.value}-${uniId}`
                    ).attr("style", "display: block");
                    d3.select(`#${nodeType.value}-${uniId}`)
                        .select(".nodes")
                        .selectAll(".node")
                        .select(".check_g_warp")
                        .attr("style", "display: block");
                }
            );
            // 点击取消
            d3.select(`#btn_cancel_${nodeType.value}-${uniId}`).on(
                "click",
                function () {
                    showCheckRect.value = false;
                    showMask();
                    _this.setState({ selectNodes: [] });
                    d3.select(`#btn_compare_${nodeType.value}-${uniId}`).attr(
                        "style",
                        "display: block"
                    );
                    d3.select(
                        `#detail_btn_warp_${nodeType.value}-${uniId}`
                    ).attr("style", "display: none");
                    d3.select(`#${nodeType.value}-${uniId}`)
                        .select(".nodes")
                        .selectAll(".node")
                        .select(".check_g_warp")
                        .attr("style", "display: none");
                    // 隐藏勾选框
                    d3.select(`#${nodeType.value}-${uniId}`)
                        .select(".nodes")
                        .selectAll(".node")
                        .select(".check_g_warp")
                        .select("path")
                        .attr("style", "display: none");
                    d3.select(`#${nodeType.value}-${uniId}`)
                        .select(".nodes")
                        .selectAll(".node")
                        .select(".check_g_warp")
                        .attr("style", "display: none");
                    // 全选按钮变回全选字段
                    let left = d3
                        .select(`#btn_all_${nodeType.value}-${uniId}`)
                        .select("rect")
                        .attr("x");
                    d3.select(`#btn_all_${nodeType.value}-${uniId}`)
                        .select("text")
                        .text("全选")
                        .attr("x", function () {
                            let textlen = this.getComputedTextLength();
                            return parseFloat(left) + (80 - textlen) / 2;
                        });
                }
            );
            // 全选按钮
            d3.select(`#btn_all_${nodeType.value}-${uniId}`).on(
                "click",
                function () {
                    let left = d3.select(this).select("rect").attr("x");
                    if (_this.state.selectNodes.length < list.length) {
                        _this.setState({ selectNodes: list });
                        d3.select(this)
                            .select("text")
                            .text("取消全选")
                            .attr("x", function () {
                                let textlen = this.getComputedTextLength();
                                return parseFloat(left) + (80 - textlen) / 2;
                            });
                        d3.select(`#${nodeType.value}-${uniId}`)
                            .select(".nodes")
                            .selectAll(".node")
                            .select(".check_g_warp")
                            .select("path")
                            .attr("style", "display: block");
                    } else {
                        _this.setState({ selectNodes: [] });
                        d3.select(this)
                            .select("text")
                            .text("全选")
                            .attr("x", function () {
                                let textlen = this.getComputedTextLength();
                                return parseFloat(left) + (80 - textlen) / 2;
                            });
                        d3.select(`#${nodeType.value}-${uniId}`)
                            .select(".nodes")
                            .selectAll(".node")
                            .select(".check_g_warp")
                            .select("path")
                            .attr("style", "display: none");
                    }
                }
            );
            // 点击确定
            d3.select(`#btn_confirm_${nodeType.value}-${uniId}`).on(
                "click",
                function () {
                    if (_this.state.selectNodes.length < 2) {
                        message.warning("请至少选择两个");
                        return;
                    }
                    _this.props.onCheck(
                        _this.state.selectNodes,
                        nodeType.value
                    );
                }
            );
        }

        // 绘制mask
        cluster
            .append("rect")
            .attr("id", `${nodeType.value}_mask-${id.value}`)
            .attr("class", "mask_rect")
            .attr("style", "display: none")
            .attr("width", width)
            .attr("height", endRectHeight);
    }
    function setLink(link, nodes, LineWarp) {
        let points = [];
        let sNode = nodes[link.source];
        let tNode = nodes[link.target];
        // console.log('sNode', sNode);
        // console.log('tNode', tNode);
        let nodeWarpRect = d3
            .select(`#node_warp-${id.value}`)
            .node()
            .getBoundingClientRect();
        let sNodeRect = d3
            .select(`#${sNode.type}_${sNode.idx}-${id.value}`)
            .node()
            .getBoundingClientRect();
        let tNodeRect = d3
            .select(`#${tNode.type}_${tNode.idx}-${id.value}`)
            .node()
            .getBoundingClientRect();
        let sx = sNodeRect.x - nodeWarpRect.x,
            tx = tNodeRect.x - nodeWarpRect.x,
            sy = sNodeRect.y - nodeWarpRect.y,
            ty = tNodeRect.y - nodeWarpRect.y;
        if (sy === ty) {
            points.push(
                { x: sx + sNodeRect.width, y: sy + img_h / 2 },
                { x: tx, y: ty + img_h / 2 }
            );
        } else {
            let x1 = sx + sNodeRect.width / 2,
                y1 = sy + sNodeRect.height;
            let x2 = tx + tNodeRect.width / 2,
                y2 = ty;
            if (x1 < x2) {
                points.push(
                    { x: x1, y: y1 },
                    { x: x1 + (x2 - x1) * 0.25, y: (y1 + y2) / 2 },
                    { x: x1 + (x2 - x1) * 0.75, y: (y1 + y2) / 2 },
                    { x: x2, y: y2 }
                );
            } else {
                if (x1 === x2 && Math.abs(y2 - y1) > space_left) {
                    points.push(
                        { x: x1, y: y1 },
                        { x: x1 + img_w + 30, y: (y1 + y2) / 2 },
                        { x: x2, y: y2 }
                    );
                } else {
                    points.push(
                        { x: x1, y: y1 },
                        { x: x1 - (x1 - x2) * 0.25, y: (y1 + y2) / 2 },
                        { x: x1 - (x1 - x2) * 0.75, y: (y1 + y2) / 2 },
                        { x: x2, y: y2 }
                    );
                }
            }
        }
        const dpath = d3
            .line()
            .x((d) => d.x)
            .y((d) => d.y)
            .curve(d3.curveBasis)(points);
        LineWarp.append("path")
            .attr("id", `line_${link.source}_${link.target}-${id.value}`)
            .attr("class", "line_path")
            .attr("style", "opacity: 1;stroke-width: 1;")
            .attr("fill", "none")
            .attr("d", dpath)
            .attr("marker-end", `url(#arrow-${id.value})`);
    }

    function setdownTooltip(nodeType, nodes) {
        let tooltipNodes = _.filter(
            nodes,
            (item) =>
                item.type === "pod" &&
                item.attribute.podLifeList &&
                item.attribute.podLifeList.length
        );
        if (tooltipNodes.length <= 0) return;
        const cluster = downTooltipWarp
            .append("g")
            .attr("id", `${nodeType.value}_tooltip_warp`);
        let tooltipNode = cluster
            .selectAll("g")
            .data(tooltipNodes)
            .enter()
            .append("g")
            .attr("id", (d) => `${d.type}_tooltip_${d.idx}`)
            .attr("class", "tooltip")
            .attr("transform", (d) => {
                let transformWarpValue = transformValueBuild(
                    d3.select(`#${d.type}`).attr("transform")
                );
                let transformValue = transformValueBuild(
                    d3.select(`#${d.type}_${d.idx}`).attr("transform")
                );
                return `translate(${
                    parseFloat(transformValue[0]) + node_w / 2
                },${
                    parseFloat(transformValue[1]) +
                    parseFloat(transformWarpValue[1])
                })`;
            });
        tooltipNode
            .append("path")
            .attr("class", "tooltip_line_path")
            .attr("fill", "#ffffff80")
            .attr(
                "d",
                "M 0,0 L -10,-10 H -68 Q -78,-10 -78,-20 V -50 Q -78,-60 -68,-60 H 68 Q 78,-60 78,-50 V -20 Q 78,-10 68,-10 H 10 z"
            );
        const downReason = tooltipNode.append("text");
        downReason
            .append("tspan")
            .text(
                (d) =>
                    `消亡原因：${d.attribute.podLifeList[0].reason.slice(
                        0,
                        15
                    )}`
            )
            .attr("x", -tooltip_w / 2 + 5)
            .attr("y", -tooltip_h + 5);
        // if(reason.length >= 20){
        downReason
            .append("tspan")
            .text((d) =>
                d.attribute.podLifeList[0].reason.length >= 35
                    ? `${d.attribute.podLifeList[0].reason.slice(15, 35)}.....`
                    : ""
            )
            .attr("x", -tooltip_w / 2 + 5)
            .attr("y", -tooltip_h + 20);
        // }
        downReason
            .append("title")
            .text((d) => `消亡原因：${d.attribute.podLifeList[0].reason}`);

        tooltipNode
            .append("text")
            .text((d) => `消亡时间：${d.attribute.podLifeList[0].timestamp}`)
            .attr("x", -tooltip_w / 2 + 5)
            .attr("y", -15)
            .append("title")
            .text((d) => `消亡时间：${d.attribute.podLifeList[0].timestamp}`);
    }
    return {
        drawArrow,
        setNode,
        setLink,
        setdownTooltip,
        id,
        chartRef,
        showCheckRect
    };
}
